#include "nano_v1.h"
#include <godot_cpp/core/class_db.hpp>

using namespace godot;


PackedByteArray NanoV1::encodeStr(const String& p_str) {
	ByteArray byte_array = Protocol::strEncode(p_str.utf8().get_data());
	PackedByteArray result;
	result.resize(byte_array.size());
	memcpy(result.ptrw(), byte_array.data(), byte_array.size());
	return result;
}

String NanoV1::decodeStr(const PackedByteArray& p_data) {
	ByteArray byte_array;
	byte_array.resize(p_data.size());
	memcpy(byte_array.data(), p_data.ptr(), p_data.size());
	return String(Protocol::strDecode(byte_array).c_str());
}

PackedByteArray NanoV1::encodePackage(const Ref<NanoPackage>& p_pkg) {
	Protocol::Package pkg;
	pkg.type = static_cast<Protocol::PackageType>(p_pkg->get_type());
	ByteArray body;
	body.resize(p_pkg->get_body().size());
	memcpy(body.data(), p_pkg->get_body().ptr(), p_pkg->get_body().size());
	pkg.body = body;
	ByteArray encoded = Protocol::packageEncode(pkg.type, pkg.body);
	PackedByteArray result;
	result.resize(encoded.size());
	memcpy(result.ptrw(), encoded.data(), encoded.size());
	return result;
}

Array NanoV1::decodePackage(const PackedByteArray& p_data) {
	Array result;
	ByteArray byte_array;
	byte_array.resize(p_data.size());
	memcpy(byte_array.data(), p_data.ptr(), p_data.size());
	std::vector<Protocol::Package> pkgs = Protocol::packageDecode(byte_array);
	for (const Protocol::Package& pkg : pkgs) {
		Ref<NanoPackage> nano_pkg;
		nano_pkg.instantiate();
		nano_pkg->initNanoPackage(pkg);
		result.append(nano_pkg);
	}
	return result;
}

PackedByteArray NanoV1::encodeMessage(const Ref<NanoMessage>& p_msg) {
	Protocol::Message msg;
	msg.id = p_msg->get_id();
	msg.type = static_cast<Protocol::MessageType>(p_msg->get_type());
	msg.compressRoute = p_msg->get_compress_route();
	msg.route = p_msg->get_route().utf8().get_data();
	ByteArray body;
	body.resize(p_msg->get_body().size());
	memcpy(body.data(), p_msg->get_body().ptr(), p_msg->get_body().size());
	msg.body = body;
	ByteArray encoded = Protocol::messageEncode(msg.id,msg.type,msg.compressRoute,msg.route,msg.body);
	PackedByteArray result;
	result.resize(encoded.size());
	memcpy(result.ptrw(), encoded.data(), encoded.size());
	return result;
}

Ref<NanoMessage> NanoV1::decodeMessage(const PackedByteArray& p_data) {
	ByteArray byte_array;
	byte_array.resize(p_data.size());
	memcpy(byte_array.data(), p_data.ptr(), p_data.size());
	Protocol::Message msg = Protocol::messageDecode(byte_array);
	Ref<NanoMessage> result;
	result.instantiate();
	result->initNanoMessage(msg);
	return result;
}

void NanoV1::_bind_methods() {


	ClassDB::bind_static_method("NanoV1", D_METHOD("encodeStr", "p_str"), &NanoV1::encodeStr);
	ClassDB::bind_static_method("NanoV1", D_METHOD("decodeStr", "p_data"), &NanoV1::decodeStr);
	ClassDB::bind_static_method("NanoV1", D_METHOD("encodePackage", "p_pkg"), &NanoV1::encodePackage);
	ClassDB::bind_static_method("NanoV1", D_METHOD("decodePackage", "p_data"), &NanoV1::decodePackage);
	ClassDB::bind_static_method("NanoV1", D_METHOD("encodeMessage", "p_msg"), &NanoV1::encodeMessage);
	ClassDB::bind_static_method("NanoV1", D_METHOD("decodeMessage", "p_data"), &NanoV1::decodeMessage);
}
